﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using KtzServer.Properties;

namespace KtzServer
{
    public partial class MainForm : Form
    {
        private Dictionary<string, int> clientSockets;
        private bool endService = true;
        private Socket serverSocket;
        private Thread serverThread;

        private byte[] step1Bytes;

        private byte[] step2Bytes;

        private byte[] step3Bytes;

        public MainForm()
        {
            InitializeComponent();
        }

        private void StartButton_Click(object sender, EventArgs e)
        {
            string ktzPath = Application.StartupPath + "\\ktz.exe";
            WindowState = FormWindowState.Minimized;
            ShowInTaskbar = false;
            Process.Start(ktzPath);
            notifyIcon.ShowBalloonTip(500);
        }

        private void EndButton_Click(object sender, EventArgs e)
        {
            serverSocket.Close();
        }

        private void ClearButton_Click(object sender, EventArgs e)
        {
            MessageTextBox.Text = string.Empty;
        }

        private void ServerSocketThread(Object socket)
        {
            Socket serverSocketIn = socket as Socket;
            if (serverSocketIn == null)
            {
                AppentLog("Not a vaild server socket.\r\n");
                return;
            }
            while (!endService)
            {
                try
                {
                    Socket clientSocket = serverSocketIn.Accept();
                    AppentLog("Accept a Client.\r\n");
                    Thread clientSocketThread = new Thread(ClientSocketthread);
                    clientSocketThread.Start(clientSocket);
                    Thread.Sleep(100);
                }
                catch (Exception e)
                {
                    AppentLog("Server error.\r\n" + e.Message + "\r\n");
                    break;
                }
            }
        }

        private void ClientSocketthread(Object osocket)
        {
            Socket clientSocket = osocket as Socket;
            byte[] buggfer = new byte[10240];
            if (clientSocket != null)
            {
                while (true)
                {
                    try
                    {
                        int len = clientSocket.Receive(buggfer, buggfer.Length, SocketFlags.None);
                        IPEndPoint remoteAddress = (IPEndPoint)clientSocket.RemoteEndPoint;
                        Monitor.Enter(clientSockets);
                        if (!clientSockets.ContainsKey(remoteAddress.Address.ToString()))
                        {
                            clientSockets.Add(remoteAddress.Address.ToString(), 0);
                        }
                        int step = clientSockets[remoteAddress.Address.ToString()];
                        step++;
                        clientSockets[remoteAddress.Address.ToString()] = step;

                        Monitor.Exit(clientSockets);

                        AppentLog(string.Format("{0} Step {1} begin.\r\n", remoteAddress, step));

                        if (step == 1)
                        {
                            SendBytes(clientSocket, step1Bytes);
                            clientSocket.Shutdown(SocketShutdown.Both);
                            clientSocket.Close();
                            AppentLog(string.Format("Step {0} done\r\n", step));
                        }
                        if (step == 2)
                        {
                            SendBytes(clientSocket, step2Bytes);
                            clientSocket.Shutdown(SocketShutdown.Both);
                            clientSocket.Close();
                            AppentLog(string.Format("Step {0} done\r\n", step));
                        }
                        if (step >= 3)
                        {
                            SendBytes(clientSocket, step3Bytes);
                            clientSocket.Shutdown(SocketShutdown.Both);
                            clientSocket.Close();
                            AppentLog(string.Format("Step {0} done\r\n", step));
                        }
                        break;
                    }
                    catch (Exception e)
                    {
                        AppentLog("Client socket error.\r\n" + e.Message + "\r\n");
                        break;
                    }
                }
            }
        }

        private static void SendBytes(Socket socket, byte[] content)
        {
            int count = content.Length;
            while (count > 0)
            {
                count -= socket.Send(content, content.Length - count, count, SocketFlags.None);
            }
        }

        private void AppentLog(string log)
        {
            if (InvokeRequired)
            {
                Invoke(new AppentLogDelegate(AppentLog), new object[] { log });
            }
            else
            {
                MessageTextBox.Text += string.Format("{0}:{1}", DateTime.Now, log);
            }
        }

        private void LoadButton_Click(object sender, EventArgs e)
        {
            try
            {
                string sstep1 = Encoding.ASCII.GetString(Resources.step1);

                string sstep2 = Encoding.ASCII.GetString(Resources.step2);

                string sstep3 = Encoding.ASCII.GetString(Resources.step3);


                string[] astep1 = sstep1.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
                string[] astep2 = sstep2.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
                string[] astep3 = sstep3.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);

                step1Bytes = ParseDataSimple(sstep1);
                step2Bytes = ParseDataSimple(sstep2);
                step3Bytes = ParseData(sstep3);

                AppentLog("load data done.\r\n");
            }
            catch (Exception ex)
            {
                AppentLog(ex.Message + "\r\n");
            }
        }

        private static byte[] ParseDataSimple(string data)
        {
            string[] dataUnits = data.Split(new string[] { " ", "\r\n" }, StringSplitOptions.RemoveEmptyEntries);

            List<byte> byteData = new List<byte>();

            for (int i = 0; i < dataUnits.Length; i++)
            {
                byteData.Add(Convert.ToByte(dataUnits[i], 16));             
            }
            return byteData.ToArray();
        }
        private static byte[] ParseData(string data)
        {
            string[] dataUnits = data.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);

            List<byte> byteData = new List<byte>();

            for (int i = 0; i < dataUnits.Length; i++)
            {
                string[] elements = dataUnits[i].Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
                for (int j = 1; j <= 16; j++)
                {
                    if (elements.Length > j)
                        byteData.Add(Convert.ToByte(elements[j], 16));
                }
            }
            return byteData.ToArray();
        }

        private void LinkLpLinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            FormAbout formAbout = new FormAbout();
            formAbout.ShowDialog(this);
        }

        private void MainForm_Resize(object sender, EventArgs e)
        {
            if (WindowState == FormWindowState.Minimized)
            {
                ShowInTaskbar = false;
                notifyIcon.ShowBalloonTip(500);
            }
        }

        private void notifyIcon_DoubleClick(object sender, EventArgs e)
        {
            ShowInTaskbar = true;
            WindowState = FormWindowState.Normal;
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (serverSocket != null) serverSocket.Close();
            notifyIcon.Visible = false;
        }

        private void showToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ShowInTaskbar = true;
            WindowState = FormWindowState.Normal;
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (serverSocket != null) serverSocket.Close();
            notifyIcon.Visible = false;
            Application.Exit();
        }

        private void reloadToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (clientSockets != null)
            {
                Monitor.Enter(clientSockets);
                clientSockets.Clear();
                Monitor.Exit(clientSockets);
            }
        }

        #region Nested type: AppentLogDelegate

        private delegate void AppentLogDelegate(string log);

        #endregion

        private void MainForm_Load(object sender, EventArgs e)
        {
            LoadButton_Click(this, new EventArgs());

            endService = false;
            clientSockets = new Dictionary<string, int>();
            serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            serverSocket.Bind(new IPEndPoint(IPAddress.Loopback, 5007));
            serverSocket.Listen(5);
            serverThread = new Thread(ServerSocketThread);
            serverThread.Start(serverSocket);
            AppentLog("Server Started.\r\n");
        }
    }
}